//打卡管理器
import 'dart:collection';
import 'dart:math';

import 'package:flut_attendance_manage/clock_model.dart';

class AttendanceManager {
  static const int ONE_DAY_MILLS = 1 * 24 * 60 * 60 * 1000;

  ///当前连续打卡天数
  int? curContDays;

  ///总得打卡天数
  int? totalDays;

  ///总的打卡次数
  int? totalTime;

  ///历史最高连续打卡天数
  int? histMaxCountDays;

  AttendanceManager._();

  ///单例
  static final AttendanceManager instance = AttendanceManager._();

  ///打卡记录表-按天分组 KEY=天
  ///日期 asc
  SplayTreeMap<String, List<ClockModel>> clockTable =
      SplayTreeMap((String k1, String k2) => k1.compareTo(k2));

  ///打卡、补卡
  ///[date] 指定打卡日期  缺省为当日打卡
  Future addClock({DateTime? date}) async {
    ///补卡传入特定日期
    DateTime? someDate = date ?? DateTime.now();
    String day = _formatTimeToDay(someDate);
    ClockModel clockModel = ClockModel(_getFullTime(someDate));

    List<ClockModel>? dayClockList = clockTable[day];
    if (dayClockList != null) {
      dayClockList.add(clockModel);
    } else {
      clockTable[day] = [clockModel];
    }

    ///更新打开统计数据
    updateStatistics();
  }

  ///移除某一次打卡
  Future removeClock(ClockModel clockModel) async {
    DateTime? date = DateTime.tryParse(clockModel.clockTime);
    var key = date != null ? _formatTimeToDay(date) : null;
    if (key != null && clockTable[key] != null) {
      clockTable[key]!.remove(clockModel);
      if (clockTable[key]!.isEmpty) {
        clockTable.remove(key);
      }

      ///更新打开统计数据
      updateStatistics();
    }
  }

  /// --------------------------UI展示项 -  计算-------------------------

  ///更新打开统计数据  - UI展示内容
  void updateStatistics() {
    totalTime = getClockTimesTotal();
    totalDays = getClockDaysTotal();
    curContDays = getClockDaysContinuousCur();
    histMaxCountDays = getClockDaysContinuousHis();
  }

  ///显示统计数据信息
  String getStatisticsInfoText() {
    return "总的打卡次数=$totalTime \n"
        "总的打卡天数=$totalDays \n"
        "当前连续打卡天数=$curContDays \n"
        "历史最高连续打卡天数=$histMaxCountDays \n"
        "\n"
        "某天的打卡记录=${getClockListWithDay(DateTime.now())?.map((e) => e.clockTime).toList().toString() ?? "无"} \n";
  }

  ///总的打卡次数
  int getClockTimesTotal() {
    int total = 0;
    for (List list in clockTable.values) {
      total += list.length;
    }
    return total;
  }

  ///总的打卡天数
  int getClockDaysTotal() {
    return clockTable.length;
  }

  ///某日打卡记录
  List<ClockModel>? getClockListWithDay(DateTime dateTime) {
    return clockTable[_formatTimeToDay(dateTime)];
  }

  ///当前连续打卡天数
  int getClockDaysContinuousCur() {
    DateTime now = DateTime.now();
    String key = _formatTimeToDay(now);
    var dateKeys = clockTable.keys.toList();
    //由目标位置向两端遍历
    int startIndex = dateKeys.indexOf(key);
    if (startIndex == -1) return 0;
    int endIndex = startIndex;
    while (true) {
      var addPre = startIndex - 1 >= 0 &&
          _isTomorrow(dateKeys[startIndex - 1], dateKeys[startIndex]) == true;
      if (addPre) {
        startIndex--;
      }
      var addAfter = endIndex + 1 < dateKeys.length &&
          _isTomorrow(dateKeys[endIndex], dateKeys[endIndex + 1]) == true;
      if (addAfter) {
        endIndex++;
      }

      ///不再追加，跳出循环
      if (!addPre && !addAfter) {
        break;
      }
    }
    return endIndex - startIndex + 1;
  }

  ///历史最高连续打卡天数
  int getClockDaysContinuousHis() {
    List<String> keysList = clockTable.keys.toList();
    if (keysList.isEmpty) return 0;

    ///记录遍历过程中的最大连续天数
    //有记录打卡日期，必有一天打卡
    int maxCount = 1;
    int anchorIndex = 0;

    ///有序队列，一轮循环找出一组连续日期
    while (anchorIndex < keysList.length) {
      int lastEqIndex = _getLastCloseIndex(keysList, anchorIndex);
      if (lastEqIndex != anchorIndex) {
        maxCount = max(maxCount, (lastEqIndex - anchorIndex) + 1);
      }
      //序列的最后一个数的下标
      anchorIndex = lastEqIndex;
      anchorIndex++;
    }
    return maxCount;
  }

  ///比较两个日期，[d2]是否为[d1]的第二天
  bool? _isTomorrow(String d1, String d2) {
    DateTime? date1, date2;
    date1 = DateTime.tryParse(d1);
    date2 = DateTime.tryParse(d2);
    if (date1 == null || date2 == null) return null;
    return date2.millisecondsSinceEpoch - date1.millisecondsSinceEpoch ==
        ONE_DAY_MILLS;
  }

  //查找和index start相同的序列中的最后一项
  int _getLastCloseIndex(List<String> list, int start) {
    if (start + 1 < list.length &&
        _isTomorrow(list[start], list[start + 1]) == true) {
      return _getLastCloseIndex(list, start + 1);
    } else {
      return start;
    }
  }

  ///时间解析天
  String _formatTimeToDay(DateTime date) {
    return "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}";
  }

  ///精确记录时间到秒
  String _getFullTime(DateTime date) {
    return "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} "
        "${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}:${date.second.toString().padLeft(2, '0')}";
  }
}
